﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DeSleeper.XPowerCfg.Properties;

namespace DeSleeper.XPowerCfg
{
    public class PowerTimeout
    {
        public PowerTimeout(TimeSpan defaultValue)
        {
            Ac = Dc = defaultValue;
        }

        public TimeSpan Ac { get; set; }
        public TimeSpan Dc { get; set; }
    }

    class ArgumentParser
    {
        public bool ShouldList { get; private set; }
        public bool ShouldQuery { get; private set; }
        public bool? ShouldCreate { get; private set; }
        public bool EnableWakeOnLan { get; private set; }
        public bool ShouldQueryWakeOnLan { get; private set; }
        public string QueryScheme { get; private set; }
        public PowerTimeout MaximumHardDriveTimeout { get; private set;}
        public PowerTimeout MaximumIdleTimeout { get; private set; }
        public PowerTimeout MaximumVideoTimeout { get; private set; }

        public string[] Args { get; private set;  }

        private static readonly TimeSpan _defaultIdle = new TimeSpan(0, 15, 0);
        private static readonly TimeSpan _defaultVideo = new TimeSpan(0, 5, 0);
        private static readonly TimeSpan _defaultHardDrive = new TimeSpan(0, 10, 0);


        public ArgumentParser(string[] args)
        {
            Args = args;
            parse();
        }

        private void parse()
        {
            MaximumIdleTimeout = new PowerTimeout(_defaultIdle);
            MaximumVideoTimeout = new PowerTimeout(_defaultVideo);
            MaximumHardDriveTimeout = new PowerTimeout(_defaultHardDrive);

            var lastArg = string.Empty;
            foreach (var arg in Args)
            {
                processArgument(lastArg, arg);
                lastArg = arg;
            }
            processArgument(lastArg, string.Empty);

            // -q + -enable-wakeonlan queries wake on lan without making other changes.
            if (EnableWakeOnLan)
            {
                ShouldQueryWakeOnLan = true;
                if (ShouldQuery)
                    EnableWakeOnLan = false;
            }

            if (ShouldCreate.GetValueOrDefault(true))
                ShouldQuery = true;
        }

        private void processArgument(string lastArg, string arg)
        {
            if (string.IsNullOrEmpty(lastArg)) return;
            // Don't process elements that are not commands.
            if (!@"/\-".Contains(lastArg[0])) return;
            // Trim command indicator.
            lastArg = lastArg.Substring(1);

            switch (lastArg.ToLowerInvariant())
            {
                case "?":
                case "help":
                    ShouldCreate = false;
                    Console.WriteLine(Resources.HelpString);
                    break;
                case "l":
                case "list":
                    ShouldCreate = false;
                    ShouldList = true;
                    break;
                case "q":
                case "query":
                    ShouldCreate = false;
                    ShouldQuery = true;
                    if (!string.IsNullOrEmpty(arg) && !@"/\-".Contains(arg[0]))
                        QueryScheme = arg;
                    break;
                case "standby-timeout":
                case "standby-timeout-ac":
                case "standby-timeout-dc":
                    if (setTimeouts(lastArg, arg, MaximumIdleTimeout, "standby"))
                        ShouldCreate = true;
                    break;
                case "monitor-timeout":
                case "monitor-timeout-ac":
                case "monitor-timeout-dc":
                    if (setTimeouts(lastArg, arg, MaximumVideoTimeout, "video"))
                        ShouldCreate = true;
                    break;
                case "disk-timeout":
                case "disk-timeout-ac":
                case "disk-timeout-dc":
                    if (setTimeouts(lastArg, arg, MaximumHardDriveTimeout, "disk"))
                        ShouldCreate = true;
                    break;
                case "enable-wakeonlan":
                    EnableWakeOnLan = true;
                    ShouldCreate = ShouldCreate ?? false;
                    break;
            }
        }

        private static bool setTimeouts(string lastArg, string arg, PowerTimeout timeout, string description)
        {
            TimeSpan maximumTimeout;
            if (!tryParseTimeout(arg, out maximumTimeout))
            {
                Console.WriteLine("Invalid {0} timeout value [{1}].  Must be either seconds or hh:mm:ss",
                                  description, arg);
                return false;
            }
            if (lastArg.EndsWith("-ac"))
                timeout.Ac = maximumTimeout;
            else if (lastArg.EndsWith("-dc"))
                timeout.Dc = maximumTimeout;
            else
                timeout.Ac = timeout.Dc = maximumTimeout;

            return true;
        }

        private static bool tryParseTimeout(string arg, out TimeSpan timeout)
        {
            if (TimeSpan.TryParse(arg, out timeout)) return true;

            double seconds;
            if (!Double.TryParse(arg, out seconds)) return false;
            timeout = TimeSpan.FromSeconds(seconds);

            return true;
        }
    }
}
